package com.zh.oauth.aop;

import com.alibaba.fastjson.JSON;
import com.zh.common.constans.AuthConstant;
import com.zh.common.entity.ElecMenu;
import com.zh.common.entity.JSONResult;
import com.zh.oauth.entity.ElecAuth;
import com.zh.oauth.entity.ElecUser;
import com.zh.oauth.service.AuthService;
import com.zh.oauth.service.ElecUserService;
import com.zh.oauth.util.AuthUtil;
import com.zh.oauth.util.MenuUtil;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@Aspect
public class MenuLog {
    private static final Logger log = LoggerFactory.getLogger(MenuLog.class);


    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AuthService authService;

    @Autowired
    private ElecUserService userService;

    @Pointcut("execution(* com.zh.oauth.controller.AuthController.addMenu(..))")
    public void addMenu() {
    }

    @Async
    @AfterReturning(value = "addMenu()", returning = "result")
    public void afterAddMenu(@NotNull JoinPoint jp, JSONResult result) {
        Map<String, String> map = new HashMap<>();
        MethodSignature methodSignature = (MethodSignature) jp.getSignature();
        Method method = methodSignature.getMethod();
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        log.info("####### 菜单添加记录 #######");
        String uName = String.valueOf(jp.getArgs()[0]);
        ElecMenu menu = (ElecMenu) jp.getArgs()[1];
        String menuName = menu.getText();
        String menuPath = menu.getLink();
        String menuDes = menu.getMenuDes();
        Long pid = menu.getPid();
        Long id = menu.getId();
        // 记录值
        map.put("menuName", menuName);
        map.put("menuPath", menuPath);
        map.put("menuDes", menuDes);
        map.put("pid", String.valueOf(pid));
        map.put("id", String.valueOf(id));
        map.put("des", result.getMessage());
        map.put("notes", apiOperation.notes());
        map.put("success", result.getSuccess() ? "1" : "0");
        String date = String.format("%1$tF %1$tT", new Date());
        map.put("_id", date);
        log.info("操作人：{},目标方法：{}", uName, method.getName());
        mongoTemplate.insert(map, uName + "MENU");
        if (result.getSuccess()) updateMenuCache(uName);
    }

    @Pointcut("execution(* com.zh.oauth.controller.AuthController.delMenu(..))")
    public void delMenu() {
    }

    @Async
    @AfterReturning(value = "delMenu()", returning = "result")
    public void afterDelMenu(@NotNull JoinPoint jp, JSONResult result) {

        Map<String, String> map = new HashMap<>();
        MethodSignature methodSignature = (MethodSignature) jp.getSignature();
        Method method = methodSignature.getMethod();
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        log.info("####### 菜单删除记录 #######");
        String uName = String.valueOf(jp.getArgs()[0]);
        ElecMenu menu = (ElecMenu) jp.getArgs()[1];
        Long pid = menu.getPid();
        Long id = menu.getId();
        String des = menu.getDes();
        // 记录值
        map.put("pid", String.valueOf(pid));
        map.put("id", String.valueOf(id));
        map.put("des", result.getMessage());
        map.put("notes", apiOperation.notes());
        map.put("success", result.getSuccess() ? "1" : "0");
        map.put("childrenNotes", des);
        String date = String.format("%1$tF %1$tT", new Date());
        map.put("_id", date);
        log.info("操作人：{},目标方法：{}", uName, method.getName());
        mongoTemplate.insert(map, uName + "MENU");
        if (result.getSuccess()) updateMenuCache(uName);
    }

    @Pointcut("execution(* com.zh.oauth.controller.AuthController.modMenu(..))")
    public void modMenu() {
    }

    @Async
    @AfterReturning(value = "modMenu()", returning = "result")
    public void afterModMenu(@NotNull JoinPoint jp, JSONResult result) {
        Map<String, String> map = new HashMap<>();
        MethodSignature methodSignature = (MethodSignature) jp.getSignature();
        Method method = methodSignature.getMethod();
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        log.info("####### 权限修改记录 #######");
        String uName = String.valueOf(jp.getArgs()[0]);
        ElecMenu menu = (ElecMenu) jp.getArgs()[1];
        String menuName = menu.getText();
        Long id = menu.getId();
        Long pid = menu.getPid();
        // 记录值
        map.put("menuName", menuName);
        map.put("id", String.valueOf(id));
        map.put("pid", String.valueOf(pid));
        map.put("notes", apiOperation.notes());
        map.put("success", result.getSuccess() ? "1" : "0");
        String date = String.format("%1$tF %1$tT", new Date());
        map.put("_id", date);
        log.info("操作人：{},目标方法：{}", uName, method.getName());
        mongoTemplate.insert(map, uName + "AUTH");
        if (result.getSuccess()) updateMenuCache(uName);

    }

    /**
     * 更新菜单Cache
     *
     * @param uName
     */
    private void updateMenuCache(String uName) {
        log.info("#######更新MENU缓存数据########");
        ElecUser userInfo = new ElecUser();
        try {
            userInfo = JSON.parseObject(JSON.toJSON(redisTemplate.opsForValue().get(uName + AuthConstant.USER_INFO)).toString(), ElecUser.class);
        } catch (Exception e) {
            log.error("未查询到{}用户的缓存信息", uName);
        }
        List<ElecMenu> menuList = userService.selectMenuByUserId(userInfo.getId());
        redisTemplate.opsForValue().set(uName + AuthConstant.REDIS_WEB_MENU_KEY, MenuUtil.getTreeData(menuList));
        log.info("#####操作日志记录完毕####");
    }
}
